package pathways;

/**
 * Title:        Pathways
 * Description:  Pure Java version of the Pathways Project.
 * Copyright:    Copyright (c) 2002
 * Company:      Ants Technologies
 * @author Veejay Sani
 * @version 1.0
 */

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;

import pathways.Database.Implementation.CDatabase;
import pathways.Database.Specialized.Visual.CSearchCompound;
import pathways.SpeciesSpace.IFinished;

public class CSpanner extends JFrame
{  
  private CDatabase db;
  private CPathway pathway1;
  private CPathway pathway2;
  private CPathway pathway3;
  private CPathway pathway4;
  private int mRowNum = 0;
  CSpannerDataGatherer sdg = null;
  CSpannerDataAnalyzerAndDrawer analyzeAndDraw = null;
  private boolean mbSuspend = false;
  private CPathway mSelectedPathway = null;
  private IFinished finishListener = null;
  
  JPanel panel1 = new JPanel();
  JButton cmdSelect1 = new JButton();
  JScrollPane scrollPane1 = new JScrollPane();
  JScrollPane scrollPane2 = new JScrollPane();
  JPanel panel2 = new JPanel();
  JButton cmdSelect2 = new JButton();
  JScrollPane scrollPane3 = new JScrollPane();
  JPanel panel3 = new JPanel();
  JButton cmdSelect3 = new JButton();
  JScrollPane scrollPane4 = new JScrollPane();
  JPanel panel4 = new JPanel();
  JButton cmdSelect4 = new JButton();
  JPanel panelInfo = new JPanel();
  JButton cmdNewSearch = new JButton();
  JButton cmdStop = new JButton();
  JLabel lblInfo = new JLabel();
  JButton cmdPreviousSet = new JButton();
  JButton cmdNextSet = new JButton();
  
  class CSpannerDataAnalyzerAndDrawer extends Thread
  {
    private volatile boolean mbSuspend = false;
    private volatile boolean mbStop = false;
       
    public void run()
    {
      while(!sdg.isFinished())
      {
        if (mbSuspend)
        {
          try {
            synchronized(this) {
               while (mbSuspend) 
                 wait();
            }
          } catch (Exception excep) {}
        }
        
        Vector v = sdg.getLevels();
        loadSet(mRowNum,v);
        
        updateInfoDisplay();
        
        try {
          this.sleep(1000);
        } catch (Exception e) {}  
      }
      
      // ok so we finished fetching the data
      cmdStop.setEnabled(false);
      cmdNewSearch.setEnabled(true);
      
      updateInfoDisplay();
      printLevels(sdg.getLevels());   
    }
    
    private void printLevels(Vector levels)
    {
      System.out.println("----------------------------");
      for (int i = 0; i < 3; i++)
      {
        Vector level = (Vector)levels.get(i);
        System.out.println("Level " + i + ": " + level.toString());
      }
    }
   
    private int getCount()
    {
      Vector levelOne = (Vector)sdg.getLevels().get(0);
      
      return levelOne.size();  
    }
      
    private void updateInfoDisplay()
    {
      String info = new String();
      
      info = "Viewing " + mRowNum + " to " + (mRowNum + 4) + ".";
      
      if (sdg.isFinished())
      {
        info = info + " Finished searching - " + getCount() + " pathways found."; 
      }
      else
      {
        info = info + " Still searching... " + getCount() + " pathways found.";
      }
      
      lblInfo.setText(info);
      lblInfo.repaint();
    }
    
    public void nextSet()
    {
      if ((mRowNum + 4) < getCount())
      {
        mRowNum = mRowNum + 4;
        reCreatePathways();
        
        lblInfo.setText("Please wait. Loading the next 4 pathways...");
        lblInfo.repaint();
        
        Vector v = sdg.getLevels();
        loadSet(mRowNum,v);
        
        updateInfoDisplay(); 
      }
    }
    
    public void prevSet()
    {
      if ((mRowNum - 4) >= 0)
      {
        mRowNum = mRowNum - 4;
        reCreatePathways(); 
        
        lblInfo.setText("Please wait. Loading the previous 4 pathways...");
        lblInfo.repaint();
        
        Vector v = sdg.getLevels();
        loadSet(mRowNum,v);
        
        updateInfoDisplay(); 
      }
    }
    
    public boolean isSuspended()
    {
      return mbSuspend; 
    }
    
    public void setSuspend(boolean suspend)
    {
      mbSuspend = suspend;  
    }
  
    private void loadVector(CPathway p, Vector levels, int rowNum)
    {
      p.loadLinearPathwayFromVector(getVector(levels,rowNum));
      p.repaint();     
    }
    
    private Vector getVector(Vector levels, int rowNum)
    {
      Vector v = new Vector();
      
      Object obj = new Integer(0); // just initilizing so that loop below executes
      
      for (int i = 0; (i < levels.size()) && (obj != null); i++)
      {
        Vector vect = (Vector)levels.get(i);
        try {
            obj = vect.get(rowNum);
        } catch (Exception e) {obj = null;}
        
        if (obj != null)
        {
          Integer intTemp = (Integer)obj;
          
          if (intTemp.intValue() > 0)
             v.add(obj);
        } 
      }
      
      return v;  
    }
    
    private void loadSet(int rowNum, Vector levels)
    {
      Vector firstLevel = (Vector)levels.get(0);
      
      if (pathway1.getReactions().size() == 0)
      {
        if (firstLevel.size() > rowNum)
        {
           //try {Thread.sleep(100);} catch(Exception e) {}
           loadVector(pathway1,levels,rowNum);
        } 
      }
      
      rowNum++;
      
      if (pathway2.getReactions().size() == 0)
      {
        if (firstLevel.size() > rowNum)
        {
           //try {Thread.sleep(100);} catch(Exception e) {}
           loadVector(pathway2,levels,rowNum);
        } 
      }
      
      rowNum++;
      
      if (pathway3.getReactions().size() == 0)
      {
        if (firstLevel.size() > rowNum)
        {
           //try {Thread.sleep(100);} catch(Exception e) {}
           loadVector(pathway3,levels,rowNum); 
        }
      }
      
      rowNum++;
      
      if (pathway4.getReactions().size() == 0)
      {
        if (firstLevel.size() > rowNum)
        {
           //try {Thread.sleep(100);} catch(Exception e) {}
           loadVector(pathway4,levels,rowNum); 
        }
      }    
    }
  }  // end of inner class
  
  public CSpanner(CDatabase database)
  {
    db = database;
    
    pathway1 = new CPathway(db);
    pathway2 = new CPathway(db);
    pathway3 = new CPathway(db);
    pathway4 = new CPathway(db);
    
    initPathway(pathway1);
    initPathway(pathway2);
    initPathway(pathway3);
    initPathway(pathway4);
    
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
        
    scrollPane1.getViewport().add(pathway1, null);
    scrollPane2.getViewport().add(pathway2, null);
    scrollPane3.getViewport().add(pathway3, null);
    scrollPane4.getViewport().add(pathway4, null);
    
    scrollPane1.getHorizontalScrollBar().setUnitIncrement(10);
    scrollPane2.getHorizontalScrollBar().setUnitIncrement(10);
    scrollPane3.getHorizontalScrollBar().setUnitIncrement(10);
    scrollPane4.getHorizontalScrollBar().setUnitIncrement(10);
    
    pack();
    setSize(800,600);
    
    setVisible(true);  
  }
  
  private void initPathway(CPathway p)
  {
    p.setOwner(this);
    
    CSubstratePainter subPainter = new CSubstratePainter();
    CEnzymePainter enzymePainter = new CEnzymePainter();
    CPathwayPainter pathwayPainter = new CPathwayPainter(subPainter,enzymePainter);
    p.setPainter(pathwayPainter);

    CSubstrateMouseListener listener = new CSubstrateMouseListener(p);
    p.setSubstrateMouseListener(listener);
    CEnzymeMouseListener enzymeListener = new CEnzymeMouseListener(p);
    p.setEnzymeMouseListener(enzymeListener);
  }
  
  public void startSpanner()
  {
    CDataForSpanner data = new CDataForSpanner();
    
    boolean bGotData = getDataForSpanner(data);
    
    if (bGotData)
    {
      cleanUp();
      
      // recreate the pathways
      reCreatePathways();
      
      mRowNum = 0;
      mbSuspend = false;
      
      CCompound sub = data.sub;
      CCompound prod = data.prod;
      int maxLevel = data.maxLevel;
      
      sdg = new CSpannerDataGatherer(db,(int)sub.getID(),maxLevel,(int)prod.getID());
      
      sdg.start();
      
      analyzeAndDraw = new CSpannerDataAnalyzerAndDrawer();
      
      analyzeAndDraw.start();
      
      cmdNewSearch.setEnabled(false);
      cmdStop.setEnabled(true);
    }
  }
  
  class CDataForSpanner
  {
    CCompound sub = null;
    CCompound prod = null;
    int maxLevel = 0;  
  }
  
  private boolean getDataForSpanner(CDataForSpanner data)
  {
    CCompound sub = null;
    CCompound prod = null;
    int maxLevel = 0;
    
    sub = searchCompound();
    
    if (sub == null)
    {
      return false;
    }
    
    prod = searchCompound();
    
    if (prod == null)
    {
      return false;  
    }
    
    boolean bValidInput = false;
    
    while(!bValidInput)
    {
      String result = (String)JOptionPane.showInputDialog(this,"Enter the highest level to search upto (smaller would lead to faster search)","Highest Level?",JOptionPane.INFORMATION_MESSAGE,null,null,"4");
      
      if (result == null)
      {
        // cancel clicked
        return false;  
      }
      
      try {
          maxLevel = Integer.parseInt(result);
          bValidInput = true;
      } catch (NumberFormatException nfe) {
        JOptionPane.showMessageDialog(this,"Invalid input.");
      }
    }
    
    data.sub = sub;
    data.prod = prod;
    data.maxLevel = maxLevel;
       
    return true;
  }
    
  private void cleanUp()
  {
    // stop any threads 
    
    if (sdg != null)
    {
      // this will also stop the analyzeAndDraw thread
      sdg.setStop(true);
    }
  }
  
  private void reCreatePathways()
  {
    pathway1.disposeAndReCreate();
    pathway2.disposeAndReCreate();
    pathway3.disposeAndReCreate();
    pathway4.disposeAndReCreate(); 
  }


  
  public CSpanner()
  {
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }
  private void jbInit() throws Exception
  {
    cmdNewSearch.setText("New Search");
    cmdNewSearch.setBounds(new Rectangle(202, 50, 127, 24));
    cmdNewSearch.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdNewSearch_actionPerformed(e);
      }
    });
    panelInfo.setBorder(BorderFactory.createEtchedBorder());
    panelInfo.setBounds(new Rectangle(6, 467, 769, 84));
    panelInfo.setLayout(null);
    this.getContentPane().setLayout(null);
    panel1.setBorder(BorderFactory.createEtchedBorder());
    panel1.setBounds(new Rectangle(3, 6, 772, 110));
    panel1.setLayout(null);
    cmdSelect1.setText("Select");
    cmdSelect1.setBounds(new Rectangle(691, 67, 78, 27));
    cmdSelect1.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdSelect1_actionPerformed(e);
      }
    });
    scrollPane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollPane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
    scrollPane1.setBounds(new Rectangle(6, 8, 679, 95));
    scrollPane2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollPane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
    scrollPane2.setBounds(new Rectangle(6, 8, 679, 95));
    panel2.setLayout(null);
    panel2.setBounds(new Rectangle(3, 124, 772, 110));
    panel2.setBorder(BorderFactory.createEtchedBorder());
    cmdSelect2.setText("Select");
    cmdSelect2.setBounds(new Rectangle(691, 67, 78, 27));
    cmdSelect2.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdSelect2_actionPerformed(e);
      }
    });
    scrollPane3.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollPane3.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
    scrollPane3.setBounds(new Rectangle(6, 8, 679, 95));
    panel3.setBorder(BorderFactory.createEtchedBorder());
    panel3.setBounds(new Rectangle(5, 240, 772, 110));
    panel3.setLayout(null);
    cmdSelect3.setText("Select");
    cmdSelect3.setBounds(new Rectangle(691, 67, 78, 27));
    cmdSelect3.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdSelect3_actionPerformed(e);
      }
    });
    scrollPane4.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollPane4.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
    scrollPane4.setBounds(new Rectangle(6, 8, 679, 96));
    panel4.setBorder(BorderFactory.createEtchedBorder());
    panel4.setBounds(new Rectangle(5, 353, 772, 110));
    panel4.setLayout(null);
    cmdSelect4.setText("Select");
    cmdSelect4.setBounds(new Rectangle(691, 67, 78, 27));
    cmdSelect4.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdSelect4_actionPerformed(e);
      }
    });
    cmdStop.setText("Stop Searching");
    cmdStop.setBounds(new Rectangle(366, 50, 162, 24));
    cmdStop.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdStop_actionPerformed(e);
      }
    });
    lblInfo.setHorizontalAlignment(SwingConstants.CENTER);
    lblInfo.setText("Information is displayed here");
    lblInfo.setBounds(new Rectangle(6, 8, 754, 32));
    cmdPreviousSet.setFont(new java.awt.Font("Dialog", 1, 12));
    cmdPreviousSet.setText("<<");
    cmdPreviousSet.setBounds(new Rectangle(5, 50, 57, 24));
    cmdPreviousSet.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdPreviousSet_actionPerformed(e);
      }
    });
    cmdNextSet.setBounds(new Rectangle(703, 50, 57, 24));
    cmdNextSet.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdNextSet_actionPerformed(e);
      }
    });
    cmdNextSet.setText(">>");
    cmdNextSet.setFont(new java.awt.Font("Dialog", 1, 12));
    this.addWindowListener(new java.awt.event.WindowAdapter()
    {
      public void windowClosed(WindowEvent e)
      {
        this_windowClosed(e);
      }
      public void windowClosing(WindowEvent e)
      {
        this_windowClosing(e);
      }
    });
    this.getContentPane().add(panel1, null);
    panel1.add(cmdSelect1, null);
    panel1.add(scrollPane1, null);
    panel2.add(cmdSelect2, null);
    panel2.add(scrollPane2, null);
    panel3.add(cmdSelect3, null);
    panel3.add(scrollPane3, null);
    this.getContentPane().add(panel2, null);
    this.getContentPane().add(panelInfo, null);
    panel4.add(cmdSelect4, null);
    panel4.add(scrollPane4, null);
    this.getContentPane().add(panel3, null);
    panelInfo.add(cmdStop, null);
    panelInfo.add(lblInfo, null);
    panelInfo.add(cmdNewSearch, null);
    panelInfo.add(cmdPreviousSet, null);
    panelInfo.add(cmdNextSet, null);
    this.getContentPane().add(panel4, null); 
  }
  
  private CCompound searchCompound()
  {
    CSearchCompound c = new CSearchCompound(true,this,db,CSearchCompound.FILTER_NONE);
    
    c.show();
    
    return c.getSelectedCompound();
  }

  void cmdStop_actionPerformed(ActionEvent e)
  {
    mbSuspend = !mbSuspend;
    
    sdg.setSuspend(mbSuspend);
    analyzeAndDraw.setSuspend(mbSuspend);
    
    if (mbSuspend == false)
    {
      synchronized (sdg) {
        sdg.notifyAll();
      }
      
      synchronized (analyzeAndDraw) {
        analyzeAndDraw.notifyAll();
      }
      
      cmdStop.setText("Stop Searching");
    }
    else
    {
      cmdStop.setText("Resume Searching"); 
    }
    
  }

  void cmdNewSearch_actionPerformed(ActionEvent e)
  {
    startSpanner();
  }

  void cmdNextSet_actionPerformed(ActionEvent e)
  {
    this.analyzeAndDraw.nextSet();
  }

  void cmdPreviousSet_actionPerformed(ActionEvent e)
  {
    this.analyzeAndDraw.prevSet();
  }

  void this_windowClosed(WindowEvent e)
  {
    
  }

  void this_windowClosing(WindowEvent e)
  {
    cleanUp();
  }

  public CPathway getSelectedPathway()
  {
    return mSelectedPathway;  
  }
  
  public void setFinishListener(IFinished listener)
  {
    finishListener = listener;  
  }
  
  void cmdSelect1_actionPerformed(ActionEvent e)
  {
    mSelectedPathway = pathway1;
    cleanUp();
    this.dispose();    
    if (finishListener != null)
       finishListener.finished();
  }

  void cmdSelect2_actionPerformed(ActionEvent e)
  {
    mSelectedPathway = pathway2;
    cleanUp();
    this.dispose();
    if (finishListener != null)
       finishListener.finished();
  }

  void cmdSelect3_actionPerformed(ActionEvent e)
  {
    mSelectedPathway = pathway3;
    cleanUp();
    this.dispose();

  }

  void cmdSelect4_actionPerformed(ActionEvent e)
  {
    mSelectedPathway = pathway4;
    cleanUp();
    this.dispose();
    if (finishListener != null)
       finishListener.finished();
  }
  
}
